package fast_chan

import (
	"gitee.com/ameise84/e3ds/queue"
	"gitee.com/ameise84/e3lock"
)

type IQueue[T any] interface {
	Wait() <-chan struct{}
	Write(a T) error
	Read(f func(T))
}

func New[T any](msgSize int32) IQueue[T] {
	return &channel[T]{
		w:   queue.NewQueue[T](int(msgSize)),
		r:   queue.NewQueue[T](int(msgSize)),
		msg: make(chan struct{}, 1),
	}
}

type channel[T any] struct {
	w   queue.IQueue[T]
	r   queue.IQueue[T]
	msg chan struct{}
	mu  e3lock.SpinLock
}

func (ts *channel[T]) Wait() <-chan struct{} {
	return ts.msg
}

func (ts *channel[T]) Write(a T) error {
	ts.mu.Lock()
	err := ts.w.Enqueue(a)
	ts.mu.Unlock()
	if err == nil {
		select {
		case ts.msg <- struct{}{}:
		default:
		}
	}
	return err
}

func (ts *channel[T]) Read(f func(T)) {
	ts.mu.Lock()
	ts.w, ts.r = ts.r, ts.w
	ts.mu.Unlock()
	for {
		ctx, err := ts.r.Dequeue()
		if err != nil {
			break
		}
		f(ctx)
	}
}
